package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.mq.message.SignInMessage;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.cglib.core.Local;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_CREATE_TIME;
import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_LIKED_TIME;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author mxl
 * @since 2024-06-26
 */
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    private final InteractionQuestionMapper questionMapper;

    private final UserClient userClient;

    private final RemarkClient remarkClient;

    private final RabbitMqHelper mqHelper;

    @Override
    public void saveReply(ReplyDTO replyDTO) {
        // 1. 获取用户id
        Long user = UserContext.getUser();

        // 2. 保存回答或者评论
        InteractionReply reply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        reply.setUserId(user);
        InteractionQuestion question = questionMapper.selectById(replyDTO.getQuestionId());;
        boolean save = this.save(reply);

        // 2.1 回答完毕想mq发送消息， 获得积分
        mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.WRITE_REPLY,
                SignInMessage.of(user, 5));

        if(!save){
            throw new DbException("回答信息保存失败");
        }
        // 3. 判断是否是回答 dto.answerId 为空则是回答
        if(replyDTO.getAnswerId() != null){
            // 3.1 如果不是回答 累加回答下的评论次数
            InteractionReply answer = this.getById(replyDTO.getAnswerId());
            answer.setReplyTimes(answer.getReplyTimes()+1);
            this.updateById(answer);
        }else{
            // 3.2 如果是回答，修改问题表最近一次回答id，同时累加问题回答次数
            question.setAnswerTimes(question.getAnswerTimes()+1);
            question.setLatestAnswerId(reply.getId());

        }
        // 4. 判断是否是学生提交 dto.isStudent为true则代表学生提交 如果是则将问题表中给i问题的status改为未查看
        if(replyDTO.getIsStudent()){
            question.setStatus(QuestionStatus.UN_CHECK);
        }
        questionMapper.updateById(question);
    }

    @Override
    public PageDTO<ReplyVO> queryPageVO(ReplyPageQuery replyPageQuery) {

        return getReplyVOPageDTO(replyPageQuery, true);
    }

    /**
     * @param replyPageQuery
     * @param isHidden 是否隐藏评论
     * @return
     */
    private PageDTO<ReplyVO> getReplyVOPageDTO(ReplyPageQuery replyPageQuery, Boolean isHidden) {
        // 0.参数校验
        if(replyPageQuery.getAnswerId() == null && replyPageQuery.getQuestionId() == null){
            throw new BadRequestException("问题id和回答id不能同时为空");
        }
        // 1. 查询数据
        Page<InteractionReply> page = this.lambdaQuery()
                .eq(replyPageQuery.getQuestionId() != null, InteractionReply::getQuestionId, replyPageQuery.getQuestionId())
                .eq(InteractionReply::getAnswerId, replyPageQuery.getAnswerId() == null ? 0L : replyPageQuery.getAnswerId())
                .eq(isHidden, InteractionReply::getHidden, false)
                .page(replyPageQuery
                        .toMpPage(new OrderItem(DATA_FIELD_NAME_LIKED_TIME, false)
                        , new OrderItem(DATA_FIELD_NAME_CREATE_TIME, true)));

        List<InteractionReply> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(0L, 0L);
        }
        // 3. 补全信息
        Set<Long> uids = new HashSet<>();
        Set<Long> targetReplyIds = new HashSet<>();
        for (InteractionReply record : records) {
            if(!record.getAnonymity()){
                uids.add(record.getUserId());
                uids.add(record.getTargetUserId());
            }
            if(record.getTargetReplyId() != null && record.getTargetReplyId() > 0){
                targetReplyIds.add(record.getTargetReplyId());
            }
        }
        // 查询目标回复 如果目标回复不是匿名 则需要查询出目标用户的信息
        if(targetReplyIds.size()>0){
            List<InteractionReply> interactionReplies = listByIds(targetReplyIds);
            Set<Long> targetUserIds = interactionReplies.stream()
//                    .filter(Predicate.not(InteractionReply::getAnonymity))
                    .map(InteractionReply::getUserId)
                    .collect(Collectors.toSet());
            uids.addAll(targetUserIds);
        }

        List<UserDTO> userDTOList = userClient.queryUserByIds(uids);
        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if(userDTOList != null){
            userDTOMap = userDTOList.stream().collect(Collectors.toMap(UserDTO::getId, c->c));
        }

        // 4. 查询点赞状态
        List<Long> BizIds = records.stream().map(InteractionReply::getId).collect(Collectors.toList());
        Set<Long> likesStatusByBizIds = remarkClient.getLikesStatusByBizIds(BizIds);

        // 封装vo
        List<ReplyVO> voList = new ArrayList<>();
        for (InteractionReply record : records) {
            ReplyVO replyVO = BeanUtils.copyBean(record, ReplyVO.class);
            if(!record.getAnonymity() || !isHidden){
                UserDTO user = userDTOMap.get(record.getUserId());
                if(user != null){
                    replyVO.setUserName(user.getName());
                    replyVO.setUserType(user.getType());
                    replyVO.setUserIcon(user.getIcon());
                }
            }
            UserDTO targetUserDto = userDTOMap.get(record.getTargetUserId());
            if(targetUserDto != null){
                replyVO.setTargetUserName(targetUserDto.getName());
            }

            if(likesStatusByBizIds.contains(replyVO.getId())){
                replyVO.setLiked(Boolean.TRUE);
            }else{
                replyVO.setLiked(Boolean.FALSE);
            }

            voList.add(replyVO);
        }
        return PageDTO.of(page, voList);
    }

    @Override
    public PageDTO<ReplyVO> queryAdminPageVO(ReplyPageQuery replyPageQuery) {
        return getReplyVOPageDTO(replyPageQuery, false);
    }

    @Override
    @Transactional
    public void hiddenReply(Long id, Boolean hidden) {
        // 1. 校验
        if(id == null || hidden == null){
            throw new BadRequestException("评论id或隐藏状态不能为空");
        }

        InteractionReply old = getById(id);
        if (old == null) {
            return;
        }

        // 2.隐藏回答
        InteractionReply reply = new InteractionReply();
        reply.setId(id);
        reply.setHidden(hidden);
        updateById(reply);

        // 3.隐藏评论，先判断是否是回答，回答才需要隐藏下属评论
        if (old.getAnswerId() != null && old.getAnswerId() != 0) {
            // 3.1.有answerId，说明自己是评论，无需处理
            return;
        }
        // 3.2.没有answerId，说明自己是回答，需要隐藏回答下的评论
        lambdaUpdate()
                .set(InteractionReply::getHidden, hidden)
                .eq(InteractionReply::getAnswerId, id)
                .update();

    }
}
